home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / cvs-1.8 / cvs-1 / cvs-1.8.1 / src / entries.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-06  |  11.3 KB  |  549 lines

  1. /*
  2.  * Copyright (c) 1992, Brian Berliner and Jeff Polk
  3.  * Copyright (c) 1989-1992, Brian Berliner
  4.  * 
  5.  * You may distribute under the terms of the GNU General Public License as
  6.  * specified in the README file that comes with the CVS 1.4 kit.
  7.  * 
  8.  * Entries file to Files file
  9.  * 
  10.  * Creates the file Files containing the names that comprise the project, from
  11.  * the Entries file.
  12.  */
  13.  
  14. #include "cvs.h"
  15. #include "getline.h"
  16.  
  17. static Node *AddEntryNode PROTO((List * list, Entnode *entnode));
  18.  
  19. static Entnode *fgetentent PROTO((FILE *));
  20. static int   fputentent PROTO((FILE *, Entnode *));
  21.  
  22. static FILE *entfile;
  23. static char *entfilename;        /* for error messages */
  24.  
  25. /*
  26.  * Construct an Entnode
  27.  */
  28. Entnode *
  29. Entnode_Create(user, vn, ts, options, tag, date, ts_conflict)
  30.     const char *user;
  31.     const char *vn;
  32.     const char *ts;
  33.     const char *options;
  34.     const char *tag;
  35.     const char *date;
  36.     const char *ts_conflict;
  37. {
  38.     Entnode *ent;
  39.     
  40.     /* Note that timestamp and options must be non-NULL */
  41.     ent = (Entnode *) xmalloc (sizeof (Entnode));
  42.     ent->user      = xstrdup (user);
  43.     ent->version   = xstrdup (vn);
  44.     ent->timestamp = xstrdup (ts ? ts : "");
  45.     ent->options   = xstrdup (options ? options : "");
  46.     ent->tag       = xstrdup (tag);
  47.     ent->date      = xstrdup (date);
  48.     ent->conflict  = xstrdup (ts_conflict);
  49.  
  50.     return ent;
  51. }
  52.  
  53. /*
  54.  * Destruct an Entnode
  55.  */
  56. void
  57. Entnode_Destroy (ent)
  58.     Entnode *ent;
  59. {
  60.     free (ent->user);
  61.     free (ent->version);
  62.     free (ent->timestamp);
  63.     free (ent->options);
  64.     if (ent->tag)
  65.     free (ent->tag);
  66.     if (ent->date)
  67.     free (ent->date);
  68.     if (ent->conflict)
  69.     free (ent->conflict);
  70.     free (ent);
  71. }
  72.  
  73. /*
  74.  * Write out the line associated with a node of an entries file
  75.  */
  76. static int write_ent_proc PROTO ((Node *, void *));
  77. static int
  78. write_ent_proc (node, closure)
  79.      Node *node;
  80.      void *closure;
  81. {
  82.     if (fputentent(entfile, (Entnode *) node->data))
  83.     error (1, errno, "cannot write %s", entfilename);
  84.  
  85.     return (0);
  86. }
  87.  
  88. /*
  89.  * write out the current entries file given a list,  making a backup copy
  90.  * first of course
  91.  */
  92. static void
  93. write_entries (list)
  94.     List *list;
  95. {
  96.     /* open the new one and walk the list writing entries */
  97.     entfilename = CVSADM_ENTBAK;
  98.     entfile = open_file (entfilename, "w+");
  99.     (void) walklist (list, write_ent_proc, NULL);
  100.     if (fclose (entfile) == EOF)
  101.     error (1, errno, "error closing %s", entfilename);
  102.  
  103.     /* now, atomically (on systems that support it) rename it */
  104.     rename_file (entfilename, CVSADM_ENT);
  105.  
  106.     /* now, remove the log file */
  107.     unlink_file (CVSADM_ENTLOG);
  108. }
  109.  
  110. /*
  111.  * Removes the argument file from the Entries file if necessary.
  112.  */
  113. void
  114. Scratch_Entry (list, fname)
  115.     List *list;
  116.     char *fname;
  117. {
  118.     Node *node;
  119.  
  120.     if (trace)
  121. #ifdef SERVER_SUPPORT
  122.     (void) fprintf (stderr, "%c-> Scratch_Entry(%s)\n",
  123.             (server_active) ? 'S' : ' ', fname);
  124. #else
  125.     (void) fprintf (stderr, "-> Scratch_Entry(%s)\n", fname);
  126. #endif
  127.  
  128.     /* hashlookup to see if it is there */
  129.     if ((node = findnode_fn (list, fname)) != NULL)
  130.     {
  131.     delnode (node);            /* delete the node */
  132. #ifdef SERVER_SUPPORT
  133.     if (server_active)
  134.         server_scratch (fname);
  135. #endif
  136.     if (!noexec)
  137.         write_entries (list);    /* re-write the file */
  138.     }
  139. }
  140.  
  141. /*
  142.  * Enters the given file name/version/time-stamp into the Entries file,
  143.  * removing the old entry first, if necessary.
  144.  */
  145. void
  146. Register (list, fname, vn, ts, options, tag, date, ts_conflict)
  147.     List *list;
  148.     char *fname;
  149.     char *vn;
  150.     char *ts;
  151.     char *options;
  152.     char *tag;
  153.     char *date;
  154.     char *ts_conflict;
  155. {
  156.     Entnode *entnode;
  157.     Node *node;
  158.  
  159. #ifdef SERVER_SUPPORT
  160.     if (server_active)
  161.     {
  162.     server_register (fname, vn, ts, options, tag, date, ts_conflict);
  163.     }
  164. #endif
  165.  
  166.     if (trace)
  167.     {
  168. #ifdef SERVER_SUPPORT
  169.     (void) fprintf (stderr, "%c-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
  170.             (server_active) ? 'S' : ' ',
  171.             fname, vn, ts ? ts : "",
  172.             ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
  173.             options, tag ? tag : "", date ? date : "");
  174. #else
  175.     (void) fprintf (stderr, "-> Register(%s, %s, %s%s%s, %s, %s %s)\n",
  176.             fname, vn, ts ? ts : "",
  177.             ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
  178.             options, tag ? tag : "", date ? date : "");
  179. #endif
  180.     }
  181.  
  182.     entnode = Entnode_Create(fname, vn, ts, options, tag, date, ts_conflict);
  183.     node = AddEntryNode (list, entnode);
  184.  
  185.     if (!noexec)
  186.     {
  187.     entfile = open_file (CVSADM_ENTLOG, "a");
  188.     
  189.     write_ent_proc (node, NULL);
  190.  
  191.         if (fclose (entfile) == EOF)
  192.             error (1, errno, "error closing %s", CVSADM_ENTLOG);
  193.     }
  194. }
  195.  
  196. /*
  197.  * Node delete procedure for list-private sticky dir tag/date info
  198.  */
  199. static void
  200. freesdt (p)
  201.     Node *p;
  202. {
  203.     struct stickydirtag *sdtp;
  204.  
  205.     sdtp = (struct stickydirtag *) p->data;
  206.     if (sdtp->tag)
  207.     free (sdtp->tag);
  208.     if (sdtp->date)
  209.     free (sdtp->date);
  210.     if (sdtp->options)
  211.     free (sdtp->options);
  212.     free ((char *) sdtp);
  213. }
  214.  
  215. static Entnode *
  216. fgetentent(fpin)
  217.     FILE *fpin;
  218. {
  219.     Entnode *ent;
  220.     char *line;
  221.     size_t line_chars_allocated;
  222.     register char *cp;
  223.     char *user, *vn, *ts, *options;
  224.     char *tag_or_date, *tag, *date, *ts_conflict;
  225.  
  226.     line = NULL;
  227.     line_chars_allocated = 0;
  228.  
  229.     ent = NULL;
  230.     while (getline (&line, &line_chars_allocated, fpin) > 0)
  231.     {
  232.     if (line[0] != '/')
  233.         continue;
  234.  
  235.     user = line + 1;
  236.     if ((cp = strchr (user, '/')) == NULL)
  237.         continue;
  238.     *cp++ = '\0';
  239.     vn = cp;
  240.     if ((cp = strchr (vn, '/')) == NULL)
  241.         continue;
  242.     *cp++ = '\0';
  243.     ts = cp;
  244.     if ((cp = strchr (ts, '/')) == NULL)
  245.         continue;
  246.     *cp++ = '\0';
  247.     options = cp;
  248.     if ((cp = strchr (options, '/')) == NULL)
  249.         continue;
  250.     *cp++ = '\0';
  251.     tag_or_date = cp;
  252.     if ((cp = strchr (tag_or_date, '\n')) == NULL)
  253.         continue;
  254.     *cp = '\0';
  255.     tag = (char *) NULL;
  256.     date = (char *) NULL;
  257.     if (*tag_or_date == 'T')
  258.         tag = tag_or_date + 1;
  259.     else if (*tag_or_date == 'D')
  260.         date = tag_or_date + 1;
  261.     
  262.     if ((ts_conflict = strchr (ts, '+')))
  263.         *ts_conflict++ = '\0';
  264.         
  265.     /*
  266.      * XXX - Convert timestamp from old format to new format.
  267.      *
  268.      * If the timestamp doesn't match the file's current
  269.      * mtime, we'd have to generate a string that doesn't
  270.      * match anyways, so cheat and base it on the existing
  271.      * string; it doesn't have to match the same mod time.
  272.      *
  273.      * For an unmodified file, write the correct timestamp.
  274.      */
  275.     {
  276.         struct stat sb;
  277.         if (strlen (ts) > 30 && stat (user, &sb) == 0)
  278.         {
  279.         char *c = ctime (&sb.st_mtime);
  280.         
  281.         if (!strncmp (ts + 25, c, 24))
  282.             ts = time_stamp (user);
  283.         else
  284.         {
  285.             ts += 24;
  286.             ts[0] = '*';
  287.         }
  288.         }
  289.     }
  290.  
  291.     ent = Entnode_Create(user, vn, ts, options, tag, date, ts_conflict);
  292.     break;
  293.     }
  294.  
  295.     free (line);
  296.     return ent;
  297. }
  298.  
  299. static int
  300. fputentent(fp, p)
  301.     FILE *fp;
  302.     Entnode *p;
  303. {
  304.     if (fprintf (fp, "/%s/%s/%s", p->user, p->version, p->timestamp) < 0)
  305.     return 1;
  306.     if (p->conflict)
  307.     {
  308.     if (fprintf (fp, "+%s", p->conflict) < 0)
  309.         return 1;
  310.     }
  311.     if (fprintf (fp, "/%s/", p->options) < 0)
  312.     return 1;
  313.  
  314.     if (p->tag)
  315.     {
  316.     if (fprintf (fp, "T%s\n", p->tag) < 0)
  317.         return 1;
  318.     }
  319.     else if (p->date)
  320.     {
  321.     if (fprintf (fp, "D%s\n", p->date) < 0)
  322.         return 1;
  323.     }
  324.     else 
  325.     {
  326.     if (fprintf (fp, "\n") < 0)
  327.         return 1;
  328.     }
  329.  
  330.     return 0;
  331. }
  332.  
  333.  
  334. /*
  335.  * Read the entries file into a list, hashing on the file name.
  336.  */
  337. List *
  338. Entries_Open (aflag)
  339.     int aflag;
  340. {
  341.     List *entries;
  342.     Entnode *ent;
  343.     char *dirtag, *dirdate;
  344.     int do_rewrite = 0;
  345.     FILE *fpin;
  346.  
  347.     /* get a fresh list... */
  348.     entries = getlist ();
  349.  
  350.     /*
  351.      * Parse the CVS/Tag file, to get any default tag/date settings. Use
  352.      * list-private storage to tuck them away for Version_TS().
  353.      */
  354.     ParseTag (&dirtag, &dirdate);
  355.     if (aflag || dirtag || dirdate)
  356.     {
  357.     struct stickydirtag *sdtp;
  358.  
  359.     sdtp = (struct stickydirtag *) xmalloc (sizeof (*sdtp));
  360.     memset ((char *) sdtp, 0, sizeof (*sdtp));
  361.     sdtp->aflag = aflag;
  362.     sdtp->tag = xstrdup (dirtag);
  363.     sdtp->date = xstrdup (dirdate);
  364.  
  365.     /* feed it into the list-private area */
  366.     entries->list->data = (char *) sdtp;
  367.     entries->list->delproc = freesdt;
  368.     }
  369.  
  370.     fpin = fopen (CVSADM_ENT, "r");
  371.     if (fpin == NULL)
  372.     error (0, errno, "cannot open %s for reading", CVSADM_ENT);
  373.     else
  374.     {
  375.     while ((ent = fgetentent (fpin)) != NULL) 
  376.     {
  377.         (void) AddEntryNode (entries, ent);
  378.     }
  379.  
  380.     fclose (fpin);
  381.     }
  382.  
  383.     fpin = fopen (CVSADM_ENTLOG, "r");
  384.     if (fpin != NULL) 
  385.     {
  386.     while ((ent = fgetentent (fpin)) != NULL) 
  387.     {
  388.         (void) AddEntryNode (entries, ent);
  389.     }
  390.     do_rewrite = 1;
  391.     fclose (fpin);
  392.     }
  393.  
  394.     if (do_rewrite && !noexec)
  395.     write_entries (entries);
  396.  
  397.     /* clean up and return */
  398.     if (dirtag)
  399.     free (dirtag);
  400.     if (dirdate)
  401.     free (dirdate);
  402.     return (entries);
  403. }
  404.  
  405. void
  406. Entries_Close(list)
  407.     List *list;
  408. {
  409.     if (list)
  410.     {
  411.     if (!noexec) 
  412.         {
  413.             if (isfile (CVSADM_ENTLOG))
  414.         write_entries (list);
  415.     }
  416.     dellist(&list);
  417.     }
  418. }
  419.  
  420.  
  421. /*
  422.  * Free up the memory associated with the data section of an ENTRIES type
  423.  * node
  424.  */
  425. static void
  426. Entries_delproc (node)
  427.     Node *node;
  428. {
  429.     Entnode *p;
  430.  
  431.     p = (Entnode *) node->data;
  432.     Entnode_Destroy(p);
  433. }
  434.  
  435. /*
  436.  * Get an Entries file list node, initialize it, and add it to the specified
  437.  * list
  438.  */
  439. static Node *
  440. AddEntryNode (list, entdata)
  441.     List *list;
  442.     Entnode *entdata;
  443. {
  444.     Node *p;
  445.  
  446.     /* was it already there? */
  447.     if ((p  = findnode_fn (list, entdata->user)) != NULL)
  448.     {
  449.     /* take it out */
  450.     delnode (p);
  451.     }
  452.  
  453.     /* get a node and fill in the regular stuff */
  454.     p = getnode ();
  455.     p->type = ENTRIES;
  456.     p->delproc = Entries_delproc;
  457.  
  458.     /* this one gets a key of the name for hashing */
  459.     /* FIXME This results in duplicated data --- the hash package shouldn't
  460.        assume that the key is dynamically allocated.  The user's free proc
  461.        should be responsible for freeing the key. */
  462.     p->key = xstrdup (entdata->user);
  463.     p->data = (char *) entdata;
  464.  
  465.     /* put the node into the list */
  466.     addnode (list, p);
  467.     return (p);
  468. }
  469.  
  470. /*
  471.  * Write out/Clear the CVS/Tag file.
  472.  */
  473. void
  474. WriteTag (dir, tag, date)
  475.     char *dir;
  476.     char *tag;
  477.     char *date;
  478. {
  479.     FILE *fout;
  480.     char tmp[PATH_MAX];
  481.  
  482.     if (noexec)
  483.     return;
  484.  
  485.     if (dir == NULL)
  486.     (void) strcpy (tmp, CVSADM_TAG);
  487.     else
  488.     (void) sprintf (tmp, "%s/%s", dir, CVSADM_TAG);
  489.  
  490.     if (tag || date)
  491.     {
  492.     fout = open_file (tmp, "w+");
  493.     if (tag)
  494.     {
  495.         if (fprintf (fout, "T%s\n", tag) < 0)
  496.         error (1, errno, "write to %s failed", tmp);
  497.     }
  498.     else
  499.     {
  500.         if (fprintf (fout, "D%s\n", date) < 0)
  501.         error (1, errno, "write to %s failed", tmp);
  502.     }
  503.     if (fclose (fout) == EOF)
  504.         error (1, errno, "cannot close %s", tmp);
  505.     }
  506.     else
  507.     if (unlink_file (tmp) < 0 && ! existence_error (errno))
  508.         error (1, errno, "cannot remove %s", tmp);
  509. }
  510.  
  511. /*
  512.  * Parse the CVS/Tag file for the current directory.
  513.  */
  514. void
  515. ParseTag (tagp, datep)
  516.     char **tagp;
  517.     char **datep;
  518. {
  519.     FILE *fp;
  520.  
  521.     if (tagp)
  522.     *tagp = (char *) NULL;
  523.     if (datep)
  524.     *datep = (char *) NULL;
  525.     fp = fopen (CVSADM_TAG, "r");
  526.     if (fp)
  527.     {
  528.     char *line;
  529.     int line_length;
  530.     size_t line_chars_allocated;
  531.  
  532.     line = NULL;
  533.     line_chars_allocated = 0;
  534.       
  535.     if ((line_length = getline (&line, &line_chars_allocated, fp)) > 0)
  536.     {
  537.         /* Remove any trailing newline.  */
  538.         if (line[line_length - 1] == '\n')
  539.             line[--line_length] = '\0';
  540.         if (*line == 'T' && tagp)
  541.         *tagp = xstrdup (line + 1);
  542.         else if (*line == 'D' && datep)
  543.         *datep = xstrdup (line + 1);
  544.     }
  545.     (void) fclose (fp);
  546.     free (line);
  547.     }
  548. }
  549.